# Mayan Calendar Structure initialization.
from mayan_cal import Base

# Class and Type initialization.
from types import ClassType
vars = vars()

def instantiate_singletons():
    # Instantiate each class in this module that derives from Base, but that is the
    # intermediate model between Base and the data class.
    #
    # Each instance is assigned to the module replacing the name of the defined class.
    # This represents singularity of each class.
    #
    # This is about taking advantage of the nature of object instances as derived
    # from Base.
    #
    # It is done in phases, so that assignment/resolution of qualities are done by
    # instance instead of class.
    #
    # First phase: instantiate seasons, assign to color-directions.
    # Second phsae: instantiate colors, timecells, chakras and digits for tribes.
    # Third phase: instantiate the tribes, tones and lunar phases.
    #
    for (n, v) in vars.items():
        if type(v) is not ClassType or not issubclass(v, Base):
            continue
        if v in (Base, ColorDirection, Chakra, Digit, Timecell, Tribe,
                 Tone, LunarPhase, Castle, Season):
            continue

        vars[n] = v()


## Intermediary class models.
class Season(Base):
    class Meta:
        attributes = ('name', 'color', 'guardian', 'aspects')
class ColorDirection(Base):
    class Meta:
        attributes = ('color', 'direction', 'effect', 'season')
    index = dict() # Shared by subclasses with no conflicts.
class Chakra(Base):
    class Meta:
        attributes = ('name', 'greek_name', 'position')
    index = dict() # Shared by subclasses with no conflicts.
class Timecell(Base):
    class Meta:
        attributes = ('name',)
    index = dict() # Shared by subclasses with no conflicts.
class Digit(Base):
    class Meta:
        attributes = ('name',)
    index = dict() # Shared by subclasses with no conflicts.

class Tribe(Base):
    class Meta:
        attributes = ('number', 'name', 'color', 'chakra', 'digit',
                      'timecell', 'action', 'power', 'essence', 'birthday')
                     # XXX pprint.saferepr fails!
                     # + ('antipode', 'analog', 'occult')
    index = dict() # Shared by subclasses with no conflicts.

    def __call__(self, birthday):
        self.birthday = birthday
        return self

class Tone(Base):
    class Meta:
        attributes = ('number', 'name', 'power', 'action', 'essence')
    index = dict() # Shared by subclasses with no conflicts.

class LunarPhase(Base):
    class Meta:
        attributes = ('name', 'phase', 'attributes', 'effects')

class Castle(Base):
    class Meta:
        attributes = ('name', 'color', 'effect')


## Seasons -- associated with color-directions.
class SeasonOfTheDog(Season):
    name = 'White Northern Dog Season of Heart'
    guardian = 'dog'
    aspects = ('emotion', 'mammality', 'heart')

class SeasonOfTheSerpent(Season):
    name = 'Red Eastern Serpent Season of Instinct'
    guardian = 'serpent'
    aspects = ('instinct', 'primality')

class SeasonOfTheEagle(Season):
    name = 'Blue Western Eagle Season of Vision'
    guardian = 'eagle'
    aspects = ('mental', 'planetary', 'visionary')

class SeasonOfTheSun(Season):
    name = 'Yellow Southern Sun Season of Enlightenment'
    guardian = 'sun'
    aspects = ('enlightenment', 'solarity')

# Instantiate seasons for color-directions.
# Todo: reverse assignment of colors to the seasons in trailing resolution phase.
instantiate_singletons()


## Colors -- shared by tribes
# Colors have corresponding directions, and the two are always
# associated with each other.
#
# They are also associated with the four seasons, although separately.
#
class WhiteNorth(ColorDirection):
    color = 'White'
    direction = 'North'
    effect = 'refines'
    season = SeasonOfTheDog

class RedEast(ColorDirection):
    color = 'Red'
    direction = 'East'
    effect = 'initiates'
    season = SeasonOfTheSerpent

class BlueWest(ColorDirection):
    color = 'Blue'
    direction = 'West'
    effect = 'transforms'
    season = SeasonOfTheEagle

class YellowSouth(ColorDirection):
    color = 'Yellow'
    direction = 'South'
    effect = 'ripens'
    season = SeasonOfTheSun


## Chakras -- shared by tribes
class Crown(Chakra):
    name = 'Crown'
    greek_name = 'DALI'
    position = 7

class ThirdEye(Chakra):
    name = 'Third Eye'
    greek_name = 'GAMMA'
    position = 6

class Throat(Chakra):
    name = 'Throat'
    greek_name = 'ALPHA'
    position = 5

class Heart(Chakra):
    name = 'Heart'
    greek_name = 'SILIO'
    position = 4

class SolarPlexus(Chakra):
    name = 'Solar Plexus'
    greek_name = 'LIMI'
    position = 3

class SecondChakra(Chakra):
    name = 'Second Chakra'
    greek_name = 'KALI'
    position = 2

class Root(Chakra):
    name = 'Root'
    greek_name = 'SELI'
    position = 1


## Timecells -- shared by tribes
class Input(Timecell):
    name = 'INPUT'

class Store(Timecell):
    name = 'STORE'

class Process(Timecell):
    name = 'PROCESS'

class Output(Timecell):
    name = 'OUTPUT'

class Matrix(Timecell):
    name = 'MATRIX'


## Digits -- Unique to tribe
class RightThumb(Digit):
    pass

class RightIndexFinger(Digit):
    pass

class RightMiddleFinger(Digit):
    name = 'right middle finger'
    side = 'right'
    place = 'middle'
    kind = 'finger'
    # code = ??

class RightRingFinger(Digit):
    pass

class RightPinkyFinger(Digit):
    pass

class LeftThumb(Digit):
    pass

class LeftIndexFinger(Digit):
    pass

class LeftMiddleFinger(Digit):
    pass

class LeftRingFinger(Digit):
    pass

class LeftPinkyFinger(Digit):
    pass

class RightBigToe(Digit):
    pass

class RightIndexToe(Digit):
    pass

class RightMiddleToe(Digit):
    pass

class RightRingToe(Digit):
    pass

class RightPinkyToe(Digit):
    pass

class LeftBigToe(Digit):
    pass

class LeftIndexToe(Digit):
    pass

class LeftMiddleToe(Digit):
    pass

class LeftRingToe(Digit):
    pass

class LeftPinkyToe(Digit):
    pass

# Instantiate constructs defined up to this point.
instantiate_singletons()


## Tribes -- 20 Solar Seals.
# Note that tribe #0 == #20 (YellowSun).  See the resolution phase below.
# ! Also, the glyphs for BlueNight and BlueMonkey look similar.
class RedDragon(Tribe):
    number = 1
    name = 'Red Dragon'

    color = RedEast
    chakra = Throat
    digit = RightIndexFinger

    timecell = Input

    action = 'nurtures'
    power = 'birth'
    essence = 'being'

    # Need to be resolved.
    antipode = 'BlueNight'
    analog = 'WhiteMirror'
    occult = 'YellowSun'

class WhiteWind(Tribe):
    number = 2
    name = 'White Wind'

    color = WhiteNorth
    chakra = Heart
    digit = RightMiddleFinger

    timecell = Input

    action = 'communicates'
    power = 'spirit'
    essence = 'breath'

    antipode = 'YellowHuman'
    analog = 'RedEarth'
    occult = 'BlueStorm'

class BlueNight(Tribe):
    number = 3
    name = 'Blue Night'

    color = BlueWest
    chakra = SolarPlexus
    digit = RightRingFinger

    timecell = Input

    action = 'dreams'
    power = 'intuition'
    essence = 'abundance'

    antipode = 'RedSkywalker'
    analog = 'YellowStar'
    occult = 'WhiteMirror'

class YellowSeed(Tribe):
    number = 4
    name = 'Yellow Seed'

    color = YellowSouth
    chakra = Root
    digit = RightPinkyFinger

    timecell = Input

    action = 'targets'
    power = 'flowering'
    essence = 'awareness'

    antipode = 'WhiteWizard'
    analog = 'BlueEagle'
    occult = 'RedEarth'

class RedSerpent(Tribe):
    number = 5
    name = 'Red Serpent'

    color = RedEast
    chakra = Crown
    digit = RightBigToe

    timecell = Store

    action = 'survives'
    power = 'life force'
    essence = 'instinct'

    antipode = 'BlueEagle'
    analog = 'WhiteWizard'
    occult = 'YellowWarrior'

class WhiteWorldbridger(Tribe):
    number = 6
    name = 'White Worldbridger'

    color = WhiteNorth
    chakra = Throat
    digit = RightIndexToe

    timecell = Store

    action = 'equalizes'
    power = 'death'
    essence = 'opportunity'

    antipode = 'YellowWarrior'
    analog = 'RedSkywalker'
    occult = 'BlueEagle'

class BlueHand(Tribe):
    number = 7
    name = 'Blue Hand'

    color = BlueWest
    chakra = Heart
    digit = RightMiddleToe

    timecell = Store

    action = 'knows'
    power = 'accomplishment'
    essence = 'healing'

    antipode = 'RedEarth'
    analog = 'YellowHuman'
    occult = 'WhiteWizard'

class YellowStar(Tribe):
    number = 8
    name = 'Yellow Star'

    color = YellowSouth
    chakra = SolarPlexus
    digit = RightRingToe

    timecell = Store

    action = 'beautifies'
    power = 'elegance'
    essence = 'art'

    antipode = 'WhiteMirror'
    analog = 'BlueNight'
    occult = 'RedSkywalker'

class RedMoon(Tribe):
    number = 9
    name = 'Red Moon'

    color = RedEast
    chakra = Root
    digit = RightPinkyToe

    timecell = Process

    action = 'purifies'
    power = 'universal water'
    essence = 'flower'

    antipode = 'BlueStorm'
    analog = 'WhiteDog'
    occult = 'YellowHuman'

class WhiteDog(Tribe):
    number = 10
    name = 'White Dog'

    color = WhiteNorth
    chakra = Crown
    digit = LeftThumb

    timecell = Process

    action = 'loves'
    power = 'loyalty'
    essence = 'heart'

    antipode = 'YellowSun'
    analog = 'RedMoon'
    occult = 'BlueMonkey'

class BlueMonkey(Tribe):
    number = 11
    name = 'Blue Monkey'

    color = BlueWest
    chakra = Throat
    digit = LeftIndexFinger

    timecell = Process

    action = 'plays'
    power = 'magic'
    essence = 'illusion'

    antipode = 'RedDragon'
    analog = 'YellowWarrior'
    occult = 'WhiteDog'

class YellowHuman(Tribe):
    number = 12
    name = 'Yellow Human'

    color = YellowSouth
    chakra = Heart
    digit = LeftMiddleFinger

    timecell = Process

    action = 'influences'
    power = 'free will'
    essence = 'wisdom'

    antipode = 'WhiteWind'
    analog = 'BlueHand'
    occult = 'RedMoon'

class RedSkywalker(Tribe):
    number = 13
    name = 'Red Skywalker'

    color = RedEast
    chakra = SolarPlexus
    digit = LeftRingFinger

    timecell = Output

    action = 'explores'
    power = 'space'
    essence = 'wakefulness'

    antipode = 'BlueNight'
    analog = 'WhiteWorldbridger'
    occult = 'YellowStar'

class WhiteWizard(Tribe):
    number = 14
    name = 'White Wizard'

    color = WhiteNorth
    chakra = Root
    digit = LeftPinkyFinger

    timecell = Output

    action = 'enchants'
    power = 'timelessness'
    essence = 'receptivity'

    antipode = 'YellowSeed'
    analog = 'RedSerpent'
    occult = 'BlueHand'

class BlueEagle(Tribe):
    number = 15
    name = 'Blue Eagle'

    color = BlueWest
    chakra = Crown
    digit = LeftBigToe

    timecell = Output

    action = 'creates'
    power = 'vision'
    essence = 'mind'

    antipode = 'RedSerpent'
    analog = 'YellowSeed'
    occult = 'WhiteWorldbridger'

class YellowWarrior(Tribe):
    number = 16
    name = 'Yellow Warrior'

    color = YellowSouth
    chakra = Throat
    digit = LeftIndexToe

    timecell = Output

    action = 'questions'
    power = 'intelligence'
    essence = 'fearlessness'

    antipode = 'WhiteWorldbridger'
    analog = 'BlueMonkey'
    occult = 'RedSerpent'

class RedEarth(Tribe):
    number = 17
    name = 'Red Earth'

    color = RedEast
    chakra = Heart
    digit = LeftMiddleToe

    timecell = Matrix

    action = 'evolves'
    power = 'synchronicity'
    essence = 'navigation'

    antipode = 'BlueHand'
    analog = 'WhiteWind'
    occult = 'YellowSeed'

class WhiteMirror(Tribe):
    number = 18
    name = 'White Mirror'

    color = WhiteNorth
    chakra = SolarPlexus
    digit = LeftRingToe

    timecell = Matrix

    action = 'evolves'
    power = 'endlessness'
    essence = 'order'

    antipode = 'YellowStar'
    analog = 'RedDragon'
    occult = 'BlueNight'

class BlueStorm(Tribe):
    number = 19
    name = 'Blue Storm'

    color = BlueWest
    chakra = Root
    digit = LeftPinkyToe

    timecell = Matrix

    action = 'catalyzes'
    power = 'self-generation'
    essence = 'energy'

    antipode = 'RedMoon'
    analog = 'YellowSun'
    occult = 'WhiteWind'

class YellowSun(Tribe):
    number = 20 # Also, 0.
    name = 'Yellow Sun'

    color = YellowSouth
    chakra = Crown
    digit = RightThumb

    timecell = Matrix

    action = 'enlightens'
    power = 'universal fire'
    essence = 'life'

    antipode = 'WhiteDog'
    analog = 'BlueStorm'
    occult = 'RedDragon'


## Tones
class Magnetic(Tone):
    number  = 1
    name    = 'Magnetic'

    power   = 'unify'
    action  = 'attract'
    essence = 'purpose'

class Lunar(Tone):
    number  = 2
    name    = 'Lunar'

    power   = 'polarize'
    action  = 'stabilize'
    essence = 'challenge'

class Electric(Tone):
    number  = 3
    name    = 'Electric'

    power   = 'activate'
    action  = 'bond'
    essence = 'service'

class SelfExisting(Tone):
    number  = 4
    name    = 'Self-Existing'

    power   = 'define'
    action  = 'measure'
    essence = 'form'

class Overtone(Tone):
    number  = 5
    name    = 'Overtone'

    power   = 'empower'
    action  = 'command'
    essence = 'radiance'

class Rhythmic(Tone):
    number  = 6
    name    = 'Rhythmic'

    power   = 'organize'
    action  = 'balance'
    essence = 'equality'

class Resonant(Tone):
    number  = 7
    name    = 'Resonant'

    power   = 'channel'
    action  = 'inspire'
    essence = 'attunement'

class Galactic(Tone):
    number  = 8
    name    = 'Galactic'

    power   = 'harmonize'
    action  = 'model'
    essence = 'integrity'

class Solar(Tone):
    number  = 9
    name    = 'Solar'

    power   = 'pulse'
    action  = 'realize'
    essence = 'intention'

class Planetary(Tone):
    number  = 10
    name    = 'Planetary'

    power   = 'perfect'
    action  = 'produce'
    essence = 'manifestation'

class Spectral(Tone):
    number  = 11
    name    = 'Spectral'

    power   = 'dissolve'
    action  = 'release'
    essence = 'liberation'

class Crystal(Tone):
    number  = 12
    name    = 'Crystal'

    power   = 'dedicate'
    action  = 'universalize'
    essence = 'cooperation'

class Cosmic(Tone):
    number  = 13
    name    = 'Cosmic'

    power   = 'endure'
    action  = 'transcend'
    essence = 'presence'


## Lunar Phases
class NewMoon(LunarPhase):
    name = 'New Moon'
    phase = 0.0  # (Or, -1.0)

    attributes = ('instinct', 'new beginning', 'seed')
    effects = ('emerge', 'renew', 'generate', 'plan', 'establish', 'initiate', 'awaken')

class Crescent(LunarPhase):
    name = 'Crescent'
    phase = 0.25

    attributes = ('foundation', 'resistance', 'resources')
    effects = ('venture', 'gather', 'fortify', 'prepare', 'filter', 'externalize',
               'advance', 'expand')

class FirstQuarter(LunarPhase):
    name = 'First Quarter'
    phase = 0.5

    attributes = ('extension', 'courage', 'balance')
    effects = ('organize', 'confront', 'motivate', 'assert', 'materialize', 'form',
               'empower', 'pursue')

class Gibbous(LunarPhase):
    name = 'Gibbous'
    phase = 0.75

    attributes = ('analysis', 'strategy', 'focus')
    effects = ('mature', 'develop', 'articulate', 'perfect', 'refine', 'discern',
               'evaluate', 'observe')

class FullMoon(LunarPhase):
    name = 'Full Moon'
    phase = 1.0

    attributes = ('illumination', 'revelation', 'climax')
    effects = ('celebrate', 'beautify', 'produce', 'receive', 'express',
               'distribute', 'intuit', 'surrender', 'fulfill')

class Disseminating(LunarPhase):
    name = 'Disseminating'
    phase = -0.25

    attributes = ('wisdom', 'self-love', 'returning')
    effects = ('heal', 'share', 'teach', 'communicate', 'demonstrate',
               'release', 'review', 'amend')

class LastQuarter(LunarPhase):
    name = 'Last Quarter'
    phase = -0.5

    attributes = ('shifting', 'visionary')
    effects = ('purify', 'assimilate', 'meditate', 'rest', 'reap',
               'recuperate', 'honor', 'reflect', 'evolve')

class Balsamic(LunarPhase):
    name = 'Balsamic'
    phase = -0.75

    attributes = ('compost', 'dormancy', 'dreamtime', 'prayer')
    effects = ('integrate', 'allow', 'nourish', 'dissolve', 'aspire')


# Initiate again for tribes, tones and phases.
instantiate_singletons()

# Resolution and back-referencing.
for (n, v) in vars.items():
    if isinstance(v, Tribe):
        v.index[n]        = v
        v.index[v.number] = v

        # Cyclic -- YellowSun.
        if v.number == 20:
            v.index[0] = v

        # Many-to-many.
        v.color.index.setdefault(n, []).append(v)
        v.chakra.index.setdefault(n, []).append(v)
        v.timecell.index.setdefault(n, []).append(v)

        # One-to-one.
        v.digit.tribe = v

        v.digit.index[n] = v.digit

        v.antipode = vars[v.antipode]
        v.analog   = vars[v.analog]
        v.occult   = vars[v.occult]

    if isinstance(v, Tone):
        v.index[n] = v
        v.index[v.number] = v

del vars, n, v

class Day(Base):
    # Pre-calculated store for day information.
    # An affirmation is derived from a Day.

    class Meta:
        attributes = ('tribe', 'tone', 'guide')

    def __init__(self, day, tribe, tone, guide):
        self.day = day # The date
        self.tribe = tribe
        self.tone = tone
        self.guide = guide

    def gettribe(self):
        return self.tribe
